package com.shareware.common.exception

import android.os.Build
import android.os.Looper
import android.os.Process
import android.util.Log
import android.widget.Toast
import com.shareware.common.getContextGlobal
import com.shareware.common.listener.Callback
import com.shareware.common.utils.ActivityExt
import com.shareware.common.utils.createFile
import com.shareware.common.utils.getAppVersionCode
import com.shareware.common.utils.getAppVersionName
import com.shareware.common.utils.getCrashPath
import com.shareware.common.utils.getCurrentTime
import com.shareware.common.utils.getDeviceId
import com.shareware.common.utils.getScreenHeight
import com.shareware.common.utils.getScreenWidth
import com.shareware.common.utils.getSimOperatorName
import com.shareware.common.utils.log
import java.io.File
import java.io.FileOutputStream
import java.util.concurrent.Executors
import kotlin.system.exitProcess

/**
 * desc: 功能描述
 * crash 监听，打印日志或上传日志到服务端
 * email: mobiledeveloper@qq.com
 */
object CrashException : Thread.UncaughtExceptionHandler {

    private var mCallback = linkedSetOf<Callback<String>>()

    private var defaultUncaughtExceptionHandler: Thread.UncaughtExceptionHandler? = null

    fun start() {
        defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler()
        Thread.setDefaultUncaughtExceptionHandler(this)
    }

    override fun uncaughtException(t: Thread, ex: Throwable) {
        ActivityExt.lifecycleCallbacks.appExit()
        val log = getExceptionInfo(ex)
        log(this.javaClass.simpleName, log)
        Executors.newSingleThreadExecutor().submit {
            Looper.prepare()
            Toast.makeText(getContextGlobal(), "很抱歉,程序发生异常,即将退出", Toast.LENGTH_SHORT)
                .show()
            Looper.loop()
        }
        mCallback.forEach {
            it.call(log)
        }
        saveToSdcard(log)
        try {
            Thread.sleep(2000)
        } catch (e: InterruptedException) {
            e.printStackTrace()
        }
        if (ActivityExt.getActivityAliveCount() == 0) {
            defaultUncaughtExceptionHandler?.uncaughtException(t, ex)
        }
        ActivityExt.finishAllActivity()
        Process.killProcess(Process.myPid())
        exitProcess(0)
    }

    private fun getExceptionInfo(ex: Throwable): String {
        return StringBuilder().append("-------------Crash Log Begin-------------\n")
            .append("Phone Id:${getDeviceId()}\n")
            .append("SimOperator:${getSimOperatorName()}\n")
            .append("ScreenWidth:${getScreenWidth()}\n")
            .append("ScreenHeight:${getScreenHeight()}\n")
            .append("VersionCode:${getAppVersionCode()}\n")
            .append("VersionName:${getAppVersionName()}\n")
            .append("Phone Manufacturer:(${Build.MANUFACTURER})\n")
            .append("Phone System Version:( ${Build.VERSION.RELEASE})\n")
            .append("Phone Model:(${Build.MODEL})\n")
            .append("${Log.getStackTraceString(ex)}\n")
            .append("-------------Crash Log End-------------\n").toString()

    }

    /**
     * 保存到SD卡
     *
     * @param log log
     */
    private fun saveToSdcard(log: String) {
        val fileName = getCurrentTime() + ".log"
        val file = File(getCrashPath(), fileName).createFile(false)
        FileOutputStream(file).use { it.write(log.toByteArray()) }
    }

    /**
     * 设置crash监听
     *
     * @param callback 发送服务器回调,send file or string.
     */
    fun setCrashExceptionListener(callback: Callback<String>) {
        mCallback.add(callback)
    }
}